#define NOMINMAX
#include "TfKLineRealTime_1M.h"
#include <core/Utility.h>
#include <uam/ServerTimeMgr.h>
#include <msgcenter/TFMsgProcess.h>
#include <tfbondlib/BondFuture.h>

static const int s_TfKLineTypeData_1M_Count = 271;

TfKLineTypeData_1M::TfKLineTypeData_1M()
{
	m_list.reserve(s_TfKLineTypeData_1M_Count);
}

void TfKLineTypeData_1M::update(const xQBTFPriceList_c& DataList, int& BeginIndex, int& EndIndex)
{
	static const auto EPSION = (float)0.00001;
	if (DataList.m_List.empty())
	{
		BeginIndex = 0;
		EndIndex = 0;
		return;
	}

	BeginIndex = s_TfKLineTypeData_1M_Count;
	EndIndex = 0;

	int Hour = 0;
	int Minute = 0;
	int Second = 0;
	int Index = 0;
	std::lock_guard<std::mutex> locker(m_mutex);

	for (auto iter = DataList.m_List.begin(); iter != DataList.m_List.end(); ++iter)
	{
		if (strlen(iter->m_UpdateTime) == 8 &&
			iter->m_UpdateTime[0] >= '0' && iter->m_UpdateTime[0] <= '9' &&
			iter->m_UpdateTime[1] >= '0' && iter->m_UpdateTime[1] <= '9' &&
			iter->m_UpdateTime[3] >= '0' && iter->m_UpdateTime[3] <= '9' &&
			iter->m_UpdateTime[4] >= '0' && iter->m_UpdateTime[4] <= '9' &&
			iter->m_UpdateTime[6] >= '0' && iter->m_UpdateTime[6] <= '9' &&
			iter->m_UpdateTime[7] >= '0' && iter->m_UpdateTime[6] <= '9' &&
			iter->m_UpdateTime[2] == ':' && iter->m_UpdateTime[5] == ':')
		{

			sscanf(iter->m_UpdateTime, "%d:%d:%d", &Hour, &Minute, &Second);
			Index =time2Index(Hour, Minute, Second);

			//补数据
			fill(Index);

			assert(Index < (int)m_list.size());
			//处理数据
			xQBTFRealTimeUnit_c& Target = m_list[Index];
			if (Target.m_Open < EPSION)
				Target.m_Open = iter->m_OpenPrice;

			Target.m_Close = iter->m_LastPrice;
			Target.m_High = std::max<float>(Target.m_High, iter->m_LastPrice);

			if (Target.m_Low < EPSION)
			{
				Target.m_Low = iter->m_LastPrice;
			}
			else
			{
				Target.m_Low = std::min<float>(Target.m_Low, iter->m_LastPrice);
			}

			Target.m_Positions = iter->m_OpenInterest;
			Target.m_Volume += iter->m_IncrementVolume;
			Target.m_Volume_Total += iter->m_Volume;
			Target.m_Amount_Total += iter->m_Turnover;

			Target.m_Tran_Time = ServerTimeMgr::instance().serverTime()/ 86400 * 86400 + (Hour - 8) * 3600 + Minute * 60 + Second;
			Target.m_Tran_Time_Msec = iter->m_UpdateMillisec;


			if (strlen(Target.m_TF_Key) == 0)
			{
				FIELDCOPY(Target.m_TF_Key, iter->m_ExchangeID);
			}

			if (strlen(Target.m_TF_ID) == 0)
			{
				FIELDCOPY(Target.m_TF_ID, iter->m_InstrumentID);
			}

			BeginIndex = std::min<int>(BeginIndex, Index);
			EndIndex = std::max<int>(EndIndex, Index);

			m_enableMakeKline = true;
		}
	}

	EndIndex += 1;
}

void TfKLineTypeData_1M::response(const std::vector<xQBTFRealTimeUnit_c>& DataList, int& BeginIndex, int& EndIndex)
{
	if (DataList.empty())
	{
		BeginIndex = 0;
		EndIndex = 0;
		return;
	}

	std::lock_guard<std::mutex> locker(m_mutex);
	for (auto iter = DataList.begin(); iter != DataList.end(); ++iter)
	{
		int Index = time2Index(iter->m_Tran_Time);
		//9：15之前9：14为第一个， 11：29为上午最后一个， 13：00为下午第一个， 15：14为下午最后一个
		//对于的GMT时间 1：15之前1：14为第一个， 3：29为上午最后一个， 5：00为下午第一个， 7：14为下午最后一个
		//补数据
		fill(Index);

		assert(Index < (int)m_list.size());
		//处理数据
		m_list[Index] = *iter;
		m_enableMakeKline = true;
	}

	BeginIndex = 0;
	EndIndex = (int)m_list.size();
}

bool TfKLineTypeData_1M::getRealtime(std::vector<xQBTFRealTimeUnit_c>& Item, int BeginIndex, int EndIndex)
{
	if (-1 == BeginIndex)
		BeginIndex = 0;

	if (-1 == EndIndex || EndIndex > 271)
		EndIndex = 271;

	if (EndIndex <= BeginIndex)
		return false;

	std::lock_guard<std::mutex> locker(m_mutex);
	EndIndex = std::min<int>(EndIndex, (int)m_list.size());
	Item.reserve(EndIndex - BeginIndex);
	for (int i = BeginIndex; i < EndIndex; ++i)
	{
		const xQBTFRealTimeUnit_c& c = m_list[i];
		if (strlen(c.m_TF_ID) != 0)
			Item.push_back(c);
	}

	return true;
}

bool TfKLineTypeData_1M::getSnapshot(xQBTFRealTimeUnit_c& Snapshot)
{
	bool ret = false;
	std::lock_guard<std::mutex> locker(m_mutex);
	if (!m_list.empty())
	{
		ret = true;
		Snapshot = *m_list.rbegin();
	}

	return ret;
}

void TfKLineTypeData_1M::getRange(int& BeginIndex, int& EndIndex)
{
	std::lock_guard<std::mutex> locker(m_mutex);
	if (m_list.empty())
	{
		BeginIndex = 0;
		EndIndex = 0;
	}
	else
	{
		BeginIndex = 0;
		EndIndex = (int)m_list.size();
	}
}

void TfKLineTypeData_1M::makeKLine(time_t t, int& BeginIndex, int& EndIndex)
{
	BeginIndex = 0;
	EndIndex = 0;

	std::lock_guard<std::mutex> locker(m_mutex);
	if (!m_list.empty())
	{
		//判断是否需要生产
		int Index = time2Index(t);
		if (Index >= (int)m_list.size())
		{
			//找到上一个有效的数据，就是时间不为0
			xQBTFRealTimeUnit_c* pActiveData = nullptr;
			for (auto iter = m_list.rbegin(); iter != m_list.rend(); ++iter)
			{
				if (iter->m_Tran_Time != 0)
				{
					pActiveData = &(*iter);
					break;
				}
			}

			if (nullptr != pActiveData)
			{
				time_t LastTime = m_list.rbegin()->m_Tran_Time;
				//开始生产数据
				BeginIndex = time2Index(LastTime) + 1;
				for (int i = BeginIndex; i <= Index; ++i)
				{
					fill(i);
					assert(i < (int)m_list.size());
					//设置数据
					xQBTFRealTimeUnit_c& Current = m_list[i];
					Current = *pActiveData;
					Current.m_Tran_Time = index2Time(i);
					Current.m_Tran_Time_Msec = 0;
					Current.m_Volume = 0;
					Current.m_High = Current.m_Low = Current.m_Open = Current.m_Close;
					log_info("make k line 1 minute, id = %s, index = %d,  open = %f, close = %f, height = %f, low = %f",
						pActiveData->m_TF_ID, i, pActiveData->m_Open, pActiveData->m_Close, pActiveData->m_High, pActiveData->m_Low);
				}
				EndIndex = Index + 1;
			}
			else
			{
				log_info("make k line 1 minute, can not find active data");
			}
		}
	}
}

void TfKLineTypeData_1M::clear()
{
	std::lock_guard<std::mutex> locker(m_mutex);
	m_list.clear();
}

int TfKLineTypeData_1M::time2Index(int hour, int minute, int second)
{
	return time2Index((hour - 8) * 3600 + minute * 60 + second);
}

int TfKLineTypeData_1M::time2Index(time_t t)
{
	auto MinuteInOneDay = (int)((t % 86400) / 60);
	//9：15之前9：14为第一个， 11：29为上午最后一个， 13：00为下午第一个， 15：14为下午最后一个
	//对于的GMT时间 1：15之前1：14为第一个， 3：29为上午最后一个， 5：00为下午第一个， 7：14为下午最后一个
	if (MinuteInOneDay > 0 && MinuteInOneDay < 75)
		return 0;
	else if (MinuteInOneDay >= 75 && MinuteInOneDay <= 209)
		return 1 + MinuteInOneDay - 75;
	else if (MinuteInOneDay > 209 && MinuteInOneDay < 435)
		return MinuteInOneDay - 300 + 136;
	else
		return 270;
}

time_t TfKLineTypeData_1M::index2Time(int index) const
{
	time_t TodayZero = ServerTimeMgr::instance().serverTime() / 86400 * 86400;
	if (index < 136)
		return TodayZero + (74 + index) * 60;
	else if (index < 271)
		return TodayZero + (164 + index) * 60;
	else
		return -1;
}

void TfKLineTypeData_1M::fill(int index)
{
	int Add = index + 1 - (int)m_list.size();
	while (Add > 0)
	{
		m_list.emplace_back();
		--Add;
	}
}

TfKLineTypeList_1M::TfKLineTypeList_1M(const char* pId, const char* pKey, TfKLineRealTime_1M* p)
	: m_id(pId), m_key(pKey), m_pMsgReceiver(p)
{

}

void TfKLineTypeList_1M::update(const xQBTFPriceList_c& DataList)
{
	int BeginIndex = 0;
	int EndIndex = 0;
	m_data.update(DataList, BeginIndex, EndIndex);

    emit m_pMsgReceiver->kLinePushDataArrived(m_id.c_str(), BeginIndex, EndIndex);
}

void TfKLineTypeList_1M::response(const std::vector<xQBTFRealTimeUnit_c>& DataList, bool finished)
{
	int BeginIndex = 0;
	int EndIndex = 0;
	m_data.response(DataList, BeginIndex, EndIndex);

	if (finished)
	{
		//补足缺失的线
		int MakeBegin = 0;
		int MakeEnd = 0;
		m_data.makeKLine(ServerTimeMgr::instance().serverTime() / 60 * 60 - 60, MakeBegin, MakeEnd);
		BeginIndex = std::min<int>(BeginIndex, MakeBegin);
		EndIndex = std::max<int>(EndIndex, MakeEnd);

		m_reqstatus = KReceived;

        emit m_pMsgReceiver->kLineReqDataArrived(m_id.c_str(), BeginIndex, EndIndex);
	}
}

bool TfKLineTypeList_1M::getRealtime(std::vector<xQBTFRealTimeUnit_c>& Item, int BeginIndex, int EndIndex)
{
	return m_data.getRealtime(Item, BeginIndex, EndIndex);
}

bool TfKLineTypeList_1M::getSnapshot(xQBTFRealTimeUnit_c& Snapshot)
{
	return m_data.getSnapshot(Snapshot);
}

void TfKLineTypeList_1M::request()
{
	if (m_reqstatus == KReceived)
	{
		int BeginIndex = 0;
		int EndIndex = 0;
		m_data.getRange(BeginIndex, EndIndex);
        emit m_pMsgReceiver->kLineReqDataArrived(m_id.c_str(), BeginIndex, EndIndex);
	}

	if (m_reqstatus == kNone)
	{
		xQBTFRealTimeReq_t reqTime;
		FIELDCOPY(reqTime.m_TF_ID, m_id.c_str());
		FIELDCOPY(reqTime.m_TF_Key, m_key.c_str());
		reqTime.m_beginTime = 0;
		reqTime.m_endTime = 0;
		qb::SSRequestMsg msg;
		msg.m_FuncID = E_FID_QB_TF_REALTIME;
		msg.m_pRequest = &reqTime;
		MessagePoster poster(&msg, qbmsg::tf::EncodeFunc);
		poster.send(m_pMsgReceiver);
	}
}

void TfKLineTypeList_1M::makeKLine(time_t t)
{
	int BeginIndex = 0;
	int EndIndex = 0;
	m_data.makeKLine(t, BeginIndex, EndIndex);
	log_info("make kline 1 minute, id = %s", m_id.c_str());
	if (BeginIndex < EndIndex)
	{
        emit m_pMsgReceiver->kLinePushDataArrived(m_id.c_str(), BeginIndex, EndIndex);
	}
}

void TfKLineTypeList_1M::tfOpen()
{
	m_data.clear();
	m_reqstatus = kNone;
}

void TfKLineTypeList_1M::registerPush()
{
	std::lock_guard<std::mutex> locker(m_mutexRegister);
	++m_registers;
	if (!m_sendPush)//TODO订阅统一管理
	{
		xQBTFPriceReq_t req;
		xQBTFInstrument_c item;
		FIELDCOPY(item.m_InstrumentID, m_id.c_str());
		FIELDCOPY(item.m_TF_Key, m_key.c_str());
		req.m_List.push_back(item);

		qb::SSRequestMsg msg;
		msg.m_FuncID = E_FID_QB_TF_PRICE_PUSH_V3;
		msg.m_pRequest = &req;

		PushMsgInfo pmi(E_FID_QB_TF_PRICE_PUSH_V3, "", nullptr);
		m_pMsgReceiver->registPush(pmi, &msg, qbmsg::tf::EncodeFunc);
	}
}

void TfKLineTypeList_1M::unRegisterPush()
{
	std::lock_guard<std::mutex> locker(m_mutexRegister);
	--m_registers;
	if (m_registers < 0)
		m_registers = 0;

	//TODO:取消订阅?
}

bool TfKLineTypeList_1M::hasReg()
{
	std::lock_guard<std::mutex> locker(m_mutexRegister);
	return m_registers == 0;
}

TfKLineRealTime_1M& TfKLineRealTime_1M::instance()
{
	static TfKLineRealTime_1M s_instance;
	return s_instance;
}

void TfKLineRealTime_1M::getKLine1M(const char* pId)
{
	std::shared_ptr<TfKLineTypeList_1M> ptrData = GetTfData(pId);
	if (nullptr == ptrData.get())
		return;

	ptrData->request();
}

bool TfKLineRealTime_1M::getRealtime(const char* pId, std::vector<xQBTFRealTimeUnit_c>& Item, int BeginIndex /*= -1*/, int EndIndex /*= -1*/)
{
	bool bRet = false;
	std::shared_ptr<TfKLineTypeList_1M> ptrData = GetTfData(pId, false);
	if (ptrData.get())
		bRet = ptrData->getRealtime(Item, BeginIndex, EndIndex);

	return bRet;
}

bool TfKLineRealTime_1M::getSnapshot(const char* pId, xQBTFRealTimeUnit_c& Snapshot)
{
	bool bRet = false;
	std::shared_ptr<TfKLineTypeList_1M> ptrData = GetTfData(pId, false);
	if (ptrData.get())
		bRet = ptrData->getSnapshot(Snapshot);

	return bRet;
}

void TfKLineRealTime_1M::registerPush(const std::string& id)
{
	std::shared_ptr<TfKLineTypeList_1M> ptrData = GetTfData(id.c_str());
	if (!ptrData)
		return;

	ptrData->registerPush();
	if (m_timerId < 0)
	{
		m_LastTime = ServerTimeMgr::instance().serverTime() / 60 * 60;
		startTimer(1000);
	}
}

void TfKLineRealTime_1M::unRegisterPush(const std::string& id)
{
	std::shared_ptr<TfKLineTypeList_1M> ptrData = GetTfData(id.c_str());
	if (!ptrData)
		return;

	ptrData->unRegisterPush();

	std::lock_guard<std::mutex> locker(m_mutex);
	for (auto ptr : m_List)
	{
		if (ptr.second->hasReg())
			return;
	}

	killTimer(m_timerId);
	m_timerId = -1;
}

void TfKLineRealTime_1M::Clear()
{
	std::lock_guard<std::mutex> locker(m_mutex);
	m_LastTime = 0;
	m_List.clear();
}

void TfKLineRealTime_1M::onDataArrived(const qb::SSAckMsg& msg)
{
	if (msg.m_FuncID == E_FID_QB_TF_REALTIME)
	{
		const xQBTFRealTimeList_c* qbReq = (xQBTFRealTimeList_c*)msg.m_pRet;
		if (!qbReq || qbReq->m_List.empty())
			return;

		std::shared_ptr<TfKLineTypeList_1M> ptrData = GetTfData(qbReq->m_List.begin()->m_TF_ID);
		if (ptrData.get())
		{
			std::vector<xQBTFRealTimeUnit_c> Data;
			Data.reserve(qbReq->m_List.size());
			for (const auto& tmp : qbReq->m_List)
			{
				Data.push_back(tmp);
			}

			ptrData->response(Data, msg.m_IsReceving == 0);
		}
	}
	else if (msg.m_FuncID == E_FID_QB_TF_PRICE_PUSH_V3)
	{
		const xQBTFPriceList_c* ret = (xQBTFPriceList_c*)msg.m_pRet;
		if (!ret) return;

		std::map<std::string, xQBTFPriceList_c>  datas;
		for (const auto& price : ret->m_List)
		{
			datas[price.m_InstrumentID].m_List.push_back(price);
		}

		for (const auto& data : datas)
		{
			std::shared_ptr<TfKLineTypeList_1M> ptrData = GetTfData(data.first.c_str(), false);
			if (ptrData)
				ptrData->update(data.second);
		}
	}
}

void TfKLineRealTime_1M::timerEvent(QTimerEvent* event)
{
	makeKLine();
}

std::shared_ptr<TfKLineTypeList_1M> TfKLineRealTime_1M::GetTfData(const char* pId, bool Add /*= true*/)
{
	std::shared_ptr<TfKLineTypeList_1M> ptrRet;
	std::lock_guard<std::mutex> locker(m_mutex);
	auto iter = m_List.find(pId);
	if (m_List.end() != iter)
	{
		ptrRet = iter->second;
	}
	else
	{
		if (Add)
		{
			CFutureArray& FutureArray = CBondFuture::instance().GetFutureArray();
			const char* pKey = nullptr;
			for (unsigned i = 0; i < FutureArray.m_data.size(); ++i)
			{
				if (strcmp(pId, FutureArray.m_data[i].m_TF_ID) == 0)
				{
					pKey = FutureArray.m_data[i].GetFutureKey();
					break;
				}
			}

			if (nullptr != pKey)
			{
				ptrRet = std::make_shared<TfKLineTypeList_1M>(pId, pKey, this);
				m_List.insert(std::make_pair(pId, ptrRet));
			}
		}
	}
	return ptrRet;
}

void TfKLineRealTime_1M::makeKLine()
{
	//判断是否需要生成， 一分钟一次
	time_t Now = ServerTimeMgr::instance().serverTime();
	int Minute = Now % 86400;
	Minute /= 60;
	if ((Minute >= 75 && Minute <= 210) || (Minute > 300 && Minute <= 435))
	{
		if (Now - m_LastTime >= 60)
		{
			m_LastTime = Now / 60 * 60;

			std::map <std::string, std::shared_ptr<TfKLineTypeList_1M> > list;
			{
				std::lock_guard<std::mutex> locker(m_mutex);
				list = m_List;
			}
	
			for (auto iter = list.begin(); iter != list.end(); ++iter)
			{
				iter->second->makeKLine(m_LastTime - 60);
			}
		}
	}
}
